package com.nulldev.util.web.HttpClient.clients.nWS;

import java.io.IOException;
import java.net.URI;
import java.util.List;
import java.util.Map;

import com.nulldev.util.data.Arrays.arrays.FastLists;
import com.nulldev.util.logging.Logger;
import com.nulldev.util.logging.LoggerFactory;
import com.nulldev.util.web.HttpClient.providers.websockets.HttpWebSocket;
import com.nulldev.util.web.HttpClient.providers.websockets.WebSocketListener;
import com.nulldev.util.web.HttpClient.providers.websockets.WebSocketListener.Message;
import com.nulldev.util.web.WebSocketAPI.WebSocket;
import com.nulldev.util.web.WebSocketAPI.WebSocketEventHandler;
import com.nulldev.util.web.WebSocketAPI.WebSocketException;
import com.nulldev.util.web.WebSocketAPI.WebSocketMessage;

public class nWSSockets implements HttpWebSocket, WebSocketEventHandler {

	private final WebSocket ws;
	private final List<WebSocketListener> listeners;

	public nWSSockets(final String url, final Map<String, String> headers) throws Exception {
		this.listeners = FastLists.list();
		this.ws = new WebSocket(new URI(url), null, headers);
		this.ws.connect();
		this.ws.setEventHandler(this);
	}

	@Override
	public void close() throws IOException {
		this.ws.close();
	}

	@Override
	public void send(String msg) {
		this.ws.send(msg);
	}

	@Override
	public void send(byte[] msg) {
		this.ws.send(msg);
	}

	@Override
	public void send(String msg, WebSocketMessageType type) {
		switch (type) {
			case BINARY:
				this.ws.send(msg.getBytes());
				break;
			case TEXT:
				this.ws.send(msg);
				break;
			default:
				throw new UnsupportedOperationException("Unknown type: " + type);
		}
	}

	@Override
	public void send(byte[] msg, WebSocketMessageType type) {
		switch (type) {
			case TEXT:
				this.ws.send(new String(msg));
				break;
			case BINARY:
				this.ws.send(msg);
				break;
			default:
				throw new UnsupportedOperationException("Unknown type: " + type);
		}
	}

	@Override
	public boolean registerListener(WebSocketListener listener) {
		return this.listeners.add(listener);
	}

	@Override
	public void onOpen() {
		this.listeners.forEach((list) -> {
			list.onConnect();
		});
	}

	@Override
	public void onMessage(WebSocketMessage message) {
		this.listeners.forEach((list) -> {
			switch (message.type()) {
				case 1: {// text
					list.onMessage(new Message(message.getText(), WebSocketMessageType.TEXT));
					break;
				}
				case 0: {
					list.onMessage(new Message(message.getBytes(), WebSocketMessageType.BINARY));
					break;
				}
				default:
					throw new UnsupportedOperationException("Unknown type: " + message.type());
			}
		});
	}

	@Override
	public void onClose() {
		this.listeners.forEach((list) -> {
			list.onClosed();
		});
	}

	@Override
	public void onError(WebSocketException e) {
		this.listeners.forEach((list) -> {
			list.onError(e);
		});
	}

	private static final Logger _log = LoggerFactory.getLogger();

	@Override
	public void onLogMessage(String msg) {
		_log.debug(msg);
	}

}
